package com.ionehe.group.common.file.cos.file;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Throwables;
import com.ionehe.group.common.file.FileServer;
import com.ionehe.group.common.file.configure.FileServerConfiguration;
import com.ionehe.group.common.file.configure.FileVendors;
import com.ionehe.group.common.file.cos.flags.CosKeyFlags;
import com.ionehe.group.common.file.enums.ContentTypeEnum;
import com.ionehe.group.common.file.exception.FileException;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.COSObject;
import com.qcloud.cos.model.COSObjectInputStream;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.region.Region;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpRequestBase;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Copyright (c) 2021 ionehe.com
 * Date: 2021/5/12
 * Time: 5:50 下午
 *
 * @author 2021年 <a href="mailto:a@ionehe.com">秀</a>
 */
@Slf4j
public class FileServerImpl implements FileServer {
    private final COSClient cosClient;
    private final String bucket;

    public FileServerImpl(FileServerConfiguration conf) {
        log.info("Cos client init ...");
        Map<String, Object> vendor = (Map<String, Object>) conf.getVendors().get(FileVendors.cos);
        String endpoint = CosKeyFlags.FLAG_ENDPOINT.get(vendor);
        this.bucket = CosKeyFlags.FLAG_BUCKET.get(vendor);
        String secretId = CosKeyFlags.FLAG_ACCESS.get(vendor);
        String secretKey = CosKeyFlags.FLAG_SECRET.get(vendor);

        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        Region region = new Region(endpoint);
        ClientConfig clientConfig = new ClientConfig(region);
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 生成 cos 客户端。
        cosClient = new COSClient(cred, clientConfig);
        log.info("Cos client init success!");
    }


    @Override
    public String write(String fileName, MultipartFile file) {
        log.info("FileServer[]write[]start!");
        if (StrUtil.isBlank(fileName) || Objects.isNull(file) || file.getSize() <= 0) {
            log.warn("FileServer[]write[]parameter illegal!");
            throw new FileException("parameter illegal");
        }

        InputStream inputStream = null;
        try {
            long size = file.getSize() / (1024 * 1024);
            log.info("FileServer[]write[]fileName:{}, size:{}", fileName, size);
            String ext = FileUtil.extName(fileName).toUpperCase();
            String contentType = ContentTypeEnum.valueOf(ext).getCentType();
            long start = System.currentTimeMillis();
            inputStream = file.getInputStream();
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(contentType);
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, fileName, inputStream, metadata);
            cosClient.putObject(putObjectRequest);
            long end = System.currentTimeMillis();
            log.info("耗时:{}毫秒", end - start);
            log.info("FileServer[]write[]success!");
            return getFileUrl(fileName);
        } catch (Exception e) {
            log.error("FileServer[]write[]error! cause:{}", Throwables.getStackTraceAsString(e));
            return null;
        } finally {
            IoUtil.close(inputStream);
        }
    }


    @Override
    public String write(String fileName, File file) {
        log.info("FileServer[]write[]start! fileName:{}", fileName);
        if (StrUtil.isBlank(fileName) || Objects.isNull(file) || FileUtil.size(file) <= 0) {
            log.warn("FileServer[]write[]parameter illegal!");
            throw new FileException("parameter illegal");
        }

        try {
            long start = System.currentTimeMillis();
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, fileName, file);
            cosClient.putObject(putObjectRequest);
            long end = System.currentTimeMillis();
            log.info("耗时:{}毫秒", end - start);
            log.info("FileServer[]write[]success!");
            return getFileUrl(fileName);
        } catch (CosClientException e) {
            log.error("FileServer[]write[]error! cause:{}", Throwables.getStackTraceAsString(e));
            return null;
        }
    }


    @Override
    public boolean delete(String fileName) {
        log.info("FileServer[]delete[]start! fileName:{}", fileName);
        if (StrUtil.isBlank(fileName)) {
            log.warn("FileServer[]write[]file is empty!");
            throw new FileException("file name can not be null");
        }

        try {
            cosClient.deleteObject(bucket, fileName);
            log.info("FileServer[]delete[]success!");
            return true;
        } catch (CosClientException e) {
            e.printStackTrace();
            return false;
        }
    }


    @Override
    public boolean delete(List<String> fileNameList) {
        for (String fileName : fileNameList) {
            if (!delete(fileName)) {
                log.warn("Error in deleting object " + fileName);
            }
        }
        return true;
    }


    @Override
    public InputStream getObject(String fileName) {
        log.info("FileServer[]getObject[]start! fileName:{}", fileName);
        if (StrUtil.isBlank(fileName)) {
            log.warn("FileServer[]write[]file is empty!");
            throw new FileException("file name can not be null");
        }

        COSObjectInputStream cosObjectInput = null;
        try {
            GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, fileName);
            COSObject cosObject = cosClient.getObject(getObjectRequest);
            cosObjectInput = cosObject.getObjectContent();
            log.info("FileServer[]getObject[]success!");
            return cosObjectInput;
        } catch (Exception e) {
            log.error("FileServer[]getObject[]bucketName:{}, fileName:{} error! cause:{}",
                    bucket, fileName, Throwables.getStackTraceAsString(e));
            return null;
        }
    }


    @Override
    public String getFileUrl(String fileName) {
        COSObject object = cosClient.getObject(bucket, fileName);
        COSObjectInputStream objectContent = object.getObjectContent();
        HttpRequestBase httpRequest = objectContent.getHttpRequest();
        return httpRequest.getURI().toString();
    }
}
